package com.siyougame.business.service.inspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.word.Word07Writer;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.siyougame.business.controller.app.vo.AppInspectCreateReqVO;
import com.siyougame.business.controller.app.vo.AppInspectItemRespVO;
import com.siyougame.business.controller.app.vo.AppInspectPageReqVO;
import com.siyougame.business.controller.app.vo.AppInspectRespVO;
import com.siyougame.business.convert.inspectItem.InspectItemConvert;
import com.siyougame.business.convert.inspectItemImg.InspectItemImgConvert;
import com.siyougame.business.dal.dataobject.inspectItem.InspectItemDO;
import com.siyougame.business.dal.dataobject.inspectItemImg.InspectItemImgDO;
import com.siyougame.business.dal.dataobject.template.TemplateDO;
import com.siyougame.business.dal.dataobject.templateItem.TemplateItemDO;
import com.siyougame.business.dal.dataobject.user.WxUserDO;
import com.siyougame.business.enums.CheckItemEnum;
import com.siyougame.business.service.inspectItem.InspectItemService;
import com.siyougame.business.service.inspectItemImg.InspectItemImgService;
import com.siyougame.business.service.template.TemplateService;
import com.siyougame.business.service.templateItem.TemplateItemService;
import com.siyougame.business.service.user.WxUserService;
import com.siyougame.common.exception.RRException;
import com.siyougame.mybatis.mybatis.core.util.MyBatisUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.List;

import com.siyougame.business.controller.admin.inspect.vo.*;
import com.siyougame.business.dal.dataobject.inspect.InspectDO;
import com.siyougame.common.pojo.PageResult;

import com.siyougame.business.convert.inspect.InspectConvert;
import com.siyougame.business.dal.mysql.inspect.InspectMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import static com.siyougame.common.exception.util.ServiceExceptionUtil.exception;
import static com.siyougame.business.enums.ErrorCodeConstants.*;

/**
 * 检查记录 Service 实现类
 *
 * @author ${table.author}
 */
@Service
@Validated
public class InspectServiceImpl extends ServiceImpl<InspectMapper,  InspectDO> implements InspectService {

    @Resource
    private InspectMapper inspectMapper;
    @Resource
    private InspectItemService inspectItemService;
    @Resource
    private InspectItemImgService inspectItemImgService;
    @Resource
    private TemplateService templateService;
    @Resource
    private TemplateItemService templateItemService;
    @Resource
    private WxUserService wxUserService;
    @Override
    public Long createInspect(InspectCreateReqVO createReqVO) {
        // 插入
        InspectDO inspect = InspectConvert.INSTANCE.convert(createReqVO);
        inspectMapper.insert(inspect);
        // 返回
        return inspect.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createInspect(AppInspectCreateReqVO createReqVO) {
        //输入校验 1、勾选Y，可上传图片，上传图片为选填；2、勾选N，可输入文字信息、可上传图片，文字信息为选填，上传图片为必填写
        TemplateDO templateDO = templateService.getById(createReqVO.getTempId());
        if (templateDO == null) {
            throw exception(TEMPLATE_NOT_EXISTS);
        }
        WxUserDO wxUserDO = wxUserService.getById(String.valueOf(StpUtil.getLoginId()));
        //保存主记录
        InspectDO inspect = InspectConvert.INSTANCE.convertApp(createReqVO);
        inspect.setXcxUserId(String.valueOf(StpUtil.getLoginId()));
        inspect.setName(createReqVO.getName());
        inspect.setDepartmentId(wxUserDO.getThirdDepartmentId());
        inspect.setUserId(wxUserDO.getThirdUserId());
        inspect.setUserName(wxUserDO.getNickname());
        this.save(inspect);
        //保存明细项目
        createReqVO.getInspectItemList().iterator().forEachRemaining(item -> {

            TemplateItemDO templateItemDO = templateItemService.getOne(Wrappers.<TemplateItemDO>lambdaQuery()
                    .eq(TemplateItemDO::getId, item.getTempItemId())
                    .eq(TemplateItemDO::getTempId, templateDO.getId()));
            if (templateItemDO == null) {
                throw exception(TEMPLATE_ITEM_NOT_EXISTS);
            }

            //todo check_v 做校验
            InspectItemDO inspectItem = InspectItemConvert.INSTANCE.convertApp(item);
            // 模板中的值checkV允许为空，如果输入值为null，则设置为空字符串
            item.setCheckV(Optional.ofNullable(item.getCheckV()).orElse(""));
            if(!CheckItemEnum.isValidValue(item.getCheckV())){
                throw new RRException("选项值不在可选范围内");
//                inspectItem.setCheckV(CheckItemEnum.NULL.getValue());
            }
            if(item.getCheckV().equals(CheckItemEnum.N.getValue())){
                //必须校验 上传有文件
                if(CollUtil.isEmpty(item.getImgList())){
                    throw new RRException("当选项为N时,请上传图片");
                }
            }
            inspectItem.setInspectId(inspect.getId());
            inspectItem.setTempName(templateDO.getName());
            inspectItem.setTempItemContent(templateItemDO.getContent());
            inspectItem.setSortRank(templateItemDO.getSortRank());
            inspectItem.setOrdNum(templateItemDO.getOrdNum());
            inspectItemService.save(inspectItem);
            //保存附件
            if(CollUtil.isNotEmpty(item.getImgList())){
                item.getImgList().iterator().forEachRemaining(img -> {
                    InspectItemImgDO inspectItemImgDO = InspectItemImgConvert.INSTANCE.convertApp(img);
                    inspectItemImgDO.setInspectId(inspect.getId());
                    inspectItemImgDO.setInspectItemId(inspectItem.getId());
                    inspectItemImgService.save(inspectItemImgDO);
                });
            }

        });
        return inspect.getId();
    }

    @Override
    public void updateInspect(InspectUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateInspectExists(updateReqVO.getId());
        // 更新
        InspectDO updateObj = InspectConvert.INSTANCE.convert(updateReqVO);
        inspectMapper.updateById(updateObj);
    }

    @Override
    public void deleteInspect(Long id) {
        // 校验存在
        this.validateInspectExists(id);
        // 删除
        inspectMapper.deleteById(id);
    }

    private void validateInspectExists(Long id) {
        if (inspectMapper.selectById(id) == null) {
            throw exception(INSPECT_NOT_EXISTS);
        }
    }

    @Override
    public InspectDO getInspect(Long id) {
        InspectDO inspectDO = inspectMapper.selectById(id);
        return inspectDO;
    }

    @Override
    public AppInspectRespVO getAppInspect(Long id) {
        WxUserDO wxUserDO = wxUserService.getById(String.valueOf(StpUtil.getLoginId()));
        InspectDO inspectDO = this.getOne(Wrappers.<InspectDO>lambdaQuery().eq(InspectDO::getId, id)
                .eq(InspectDO::getDepartmentId, wxUserDO.getThirdDepartmentId()));
        if(inspectDO == null){
            throw exception(INSPECT_NOT_EXISTS);
        }
        AppInspectRespVO appInspectRespVO = InspectConvert.INSTANCE.convertApp(inspectDO);
        //封装明细
        List<InspectItemDO> list = inspectItemService.list(Wrappers.<InspectItemDO>lambdaQuery().eq(InspectItemDO::getInspectId, id));

        if (CollUtil.isNotEmpty(list)) {
            List<AppInspectItemRespVO> appInspectItemRespVOS = InspectItemConvert.INSTANCE.convertAppList(list);
            appInspectItemRespVOS.iterator().forEachRemaining(item -> {
                List<InspectItemImgDO> imgList = inspectItemImgService.list(Wrappers.<InspectItemImgDO>lambdaQuery()
                        .eq(InspectItemImgDO::getInspectId, id)
                        .eq(InspectItemImgDO::getInspectItemId, item.getId()));
                if (CollUtil.isNotEmpty(imgList)) {
                    item.setImgList(InspectItemImgConvert.INSTANCE.convertAppList(imgList));
                }
            });
            appInspectRespVO.setInspectItemList(appInspectItemRespVOS);
        }
        return appInspectRespVO;
    }

    @Override
    public void getAppInspectForExport(Long id, HttpServletResponse response) {
        InspectDO inspectDO = this.getOne(Wrappers.<InspectDO>lambdaQuery().eq(InspectDO::getId, id)
                .eq(InspectDO::getXcxUserId, StpUtil.getLoginId()));
        if(inspectDO == null){
            throw exception(INSPECT_NOT_EXISTS);
        }


        // 创建 Word07Writer
        Word07Writer writer = new Word07Writer();

        // 1. 添加文本
        Font font = new Font("微软雅黑", Font.BOLD, 14);
        writer = addText(writer, font, "标题:"+inspectDO.getTitle());
        writer = addText(writer, font, "船只:"+inspectDO.getVessels());
        writer = addText(writer, font, "日期:"+ LocalDateTimeUtil.format(inspectDO.getInspectDay(), "yyyy-MM-dd"));
        writer = addText(writer, font, "地点:"+inspectDO.getAddress());
        writer = addText(writer, font, "-------------------------------------------");


        //封装明细
        List<InspectItemDO> list = inspectItemService.list(Wrappers.<InspectItemDO>lambdaQuery()
                .eq(InspectItemDO::getInspectId, id).orderByAsc(InspectItemDO::getSortRank));

        if (CollUtil.isNotEmpty(list)) {
            for (InspectItemDO item : list) {
                writer = addText(writer, font, item.getSortRank()+"."+item.getTempItemContent());
                addSelectionToWord(writer.getDoc(), item.getCheckV());
                List<String> imgList = inspectItemImgService.listObjs(Wrappers.<InspectItemImgDO>lambdaQuery()
                                .select(InspectItemImgDO::getImgUrl)
                        .eq(InspectItemImgDO::getInspectId, id)
                        .eq(InspectItemImgDO::getInspectItemId, item.getId()),img->(String)img);
                if (CollUtil.isNotEmpty(imgList)) {
                    addImages(writer.getDoc(), imgList);
                }
                if(StrUtil.isNotBlank(item.getRemark())){
                    addText(writer, font,"备注:"+item.getRemark());
                }
            }
        }

        // 设置 HTTP 响应头，返回文件
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        response.setHeader("Content-Disposition", "attachment; filename=export.docx");

        try (OutputStream out = response.getOutputStream()) {
            writer.flush(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }
    /**
     * 向 Word07Writer 添加带自定义字体的文本
     *
     * @param writer Word07Writer
     * @param font   AWT 字体对象
     * @param texts  需要添加的文本
     * @return Word07Writer
     */
    public static Word07Writer addText(Word07Writer writer, Font font, String... texts) {
        if (writer == null) {
            throw new IllegalArgumentException("Word07Writer 不能为空");
        }
        if (font == null) {
            throw new IllegalArgumentException("Font 不能为空");
        }

        XWPFDocument document = writer.getDoc();
        for (String text : texts) {
            XWPFParagraph paragraph = document.createParagraph(); // 创建段落
            XWPFRun run = paragraph.createRun(); // 创建文本
            run.setText(text);

            // 设置字体
            run.setFontFamily(font.getFontName());  // 字体名称，如 "微软雅黑"
            run.setFontSize(font.getSize());        // 字体大小

            // 处理加粗、斜体等格式
            if (font.isBold()) {
                run.setBold(true);
            }
            if (font.isItalic()) {
                run.setItalic(true);
            }
        }
        return writer;
    }
    /**
     * 向 Word07Writer 添加图片
     *
     * @param writer    Word07Writer
     * @param imageUrls 图片地址列表
     * @return Word07Writer
     */
    /**
     * 下载图片并插入到 Word 文档中
     */
    public static void addImages(XWPFDocument doc, List<String> imageUrls) {
        for (String imageUrl : imageUrls) {
            try {
                // 读取图片流
                URL url = URLUtil.url(imageUrl);
                InputStream imageStream = url.openStream();

                // 创建段落
                XWPFParagraph paragraph = doc.createParagraph();
                XWPFRun run = paragraph.createRun();

                // 插入图片（单位 EMU）
                run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_JPEG, "image.jpg",
                        300 * 9525, 200 * 9525);

                imageStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 根据选中的数据项值插入带对勾的方框到 Word 文档
     * 格式为：☑ Y、☐ N、☐ N/A
     */
    public static void addSelectionToWord(XWPFDocument doc, String selectedValue) {
        // 创建段落
        XWPFParagraph paragraph = doc.createParagraph();
        XWPFRun run = paragraph.createRun();
        // 枚举遍历，动态插入 Y, N, N/A 选项
        for (CheckItemEnum item : CheckItemEnum.values()) {
            addCheckBox(run, item, selectedValue);  // 为每个选项添加勾选框和文本
        }
    }
    /**
     * 添加带对勾的方框并显示选项值
     */
    private static void addCheckBox(XWPFRun run, CheckItemEnum item, String selectedValue) {
        if (item.getValue().equalsIgnoreCase(selectedValue)) {
            run.setText("☑ " + item.getValue() + " "); // 选中项，带对勾的方框
        } else {
            run.setText("☐ " + item.getValue() + " "); // 未选中项，空方框
        }
        run.addTab(); // 每个选项之间添加间隔
    }
    @Override
    public List<InspectDO> getInspectList(Collection<Long> ids) {
        return inspectMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<InspectDO> getInspectPage(InspectPageReqVO pageReqVO) {
        IPage<InspectDO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        QueryWrapper<InspectDO> queryWrapper = new QueryWrapper<InspectDO>()
                .eq("a.department_id", pageReqVO.getDepartmentId())
                .like(StrUtil.isNotBlank(pageReqVO.getTitle()), "title", pageReqVO.getTitle())
                .like(StrUtil.isNotBlank(pageReqVO.getVessels()), "vessels", pageReqVO.getVessels());
        queryWrapper.eq("a.deleted", 0);
        queryWrapper.orderByDesc("a.create_time");
        IPage<InspectDO> inspectDOIPage = inspectMapper.pageList(mpPage, queryWrapper);
        PageResult<InspectDO> inspectDOPageResult = new PageResult<>(inspectDOIPage.getRecords(), inspectDOIPage.getTotal());;
        return inspectDOPageResult;
    }

    @Override
    public PageResult<InspectDO> getInspectPage(AppInspectPageReqVO pageReqVO) {

        WxUserDO wxUserDO = wxUserService.getById(String.valueOf(StpUtil.getLoginId()));
        pageReqVO.setDepartmentId(wxUserDO.getThirdDepartmentId());
        //pageReqVO.setUserId(wxUserDO.getThirdUserId());
        return inspectMapper.selectAppPage(pageReqVO);
    }
    //
    //@Override
    //public List<InspectDO> getInspectList(InspectExportReqVO exportReqVO) {
    //    return inspectMapper.selectList(exportReqVO);
    //}

}
